home *** CD-ROM | disk | FTP | other *** search
- (********************************************************************)
- (* CollStrL.PAS *)
- (* Sorted String List class that uses collation tables *)
- (* *)
- (* (c) Julian M Bucknall, 1997 *)
- (********************************************************************)
-
- { Notes:
- The TCollStringList class is an example of how to use the collation
- class from the COLLATE unit.
-
- Internally the string list maintains for each item a string, an
- object reference and a sort string. The sort string is maintained
- by the class for each string and is used for rapid searching through
- the items in the list (see the Find method).
-
- Some brief documentation (it pays to know what Delphi's TStringList
- can do, this class mimics it to a certain extent):
-
- constructor Create(aCollFileName : string);
- - creates an instance of the sorted list, aCollFileName is the
- name of a collation table file. It internally creates a
- TCollation object.
-
- destructor Destroy;
- - destroys the instance, releasing all memory back to the heap.
-
- function Add(const aSt : string) : integer;
- - adds a string to the list. The integer result is the index of
- the newly added string. If a string already exists in the list
- that compares equal to this one an ECollStringList exception is
- raised.
-
- procedure Delete(aIndex : integer);
- - deletes a string from the list. Any object associated with the
- string is NOT freed. If the index passed is out of range an
- ECollStringList exception is raised.
-
- function Find(const aSt : string; var aIndex : integer) : boolean;
- - finds a string in the list. If found, aIndex is its index and
- the function result is true. If not found, aIndex is the index
- at which the string should be inserted and the function result
- is false.
-
- property Count : integer
- - a read-only property for the number of strings in the list.
-
- property Strings [aIndex : integer] : string
- - a read-only array property that enables you to treat the string
- list as a string array. It's the default array property. If the
- index passed is out of range an ECollStringList exception is
- raised.
-
- property Objects [aIndex : integer] : TObject
- - an array property that enables you to associate an object with
- each string in the list. If the index passed is out of range an
- ECollStringList exception is raised.
-
- It has various limitations, which can be fairly easily solved:
- - there can be no duplicate strings in the list (ie, strings added
- which the collation class reports as equal to strings in the
- list are rejected);
- - the list is always sorted, unlike TStringList you cannot
- maintain the list in an unsorted order;
- - the algorithm for growing the list is very simplistic: the list
- is grown by 32 elements whenever needed. Memory for the internal
- array is only released with Destroy;
- - no method is provided to replace the collation object and to
- re-sort the list.
- }
-
- unit CollStrL;
-
- interface
-
- uses
- SysUtils,
- Collate;
-
- type
- ECollStringList = class(Exception);
-
- type
- TCollStrItem = packed record
- csiStr : string;
- csiSS : TSortString;
- csiObj : TObject;
- end;
-
- PCollStrArray = ^TCollStrArray;
- TCollStrArray = array [0..pred(MaxInt div sizeof(TCollStrItem))]
- of TCollStrItem;
-
- type
- TCollStringList = class
- protected {private}
- FCollation : TCollation;
- FList : PCollStrArray;
- FListSize : integer;
- FListCount : integer;
- protected
- function GetObject(aIndex : integer) : TObject;
- function GetString(aIndex : integer) : string;
- procedure SetObject(aIndex : integer; aObj : TObject);
-
- procedure Grow;
- public
- constructor Create(aCollFileName : string);
- destructor Destroy; override;
- function Add(const aSt : string) : integer;
- procedure Delete(aIndex : integer);
- function Find(const aSt : string; var aIndex : integer) : boolean;
-
- property Count : integer
- read FListCount;
- property Strings [aIndex : integer] : string
- read GetString; default;
- property Objects [aIndex : integer] : TObject
- read GetObject write SetObject;
- end;
-
- implementation
-
- const
- ListDelta = 32;
-
- {===TCollStringList==================================================}
- constructor TCollStringList.Create(aCollFileName : string);
- begin
- inherited Create;
- FCollation := TCollation.Create;
- FCollation.LoadFromFile(aCollFileName);
- Grow;
- end;
- {--------}
- destructor TCollStringList.Destroy;
- begin
- FreeMem(FList, FListSize * sizeof(TCollStrItem));
- FCollation.Free;
- inherited Destroy;
- end;
- {--------}
- function TCollStringList.Add(const aSt : string) : integer;
- begin
- if Find(aSt, Result) then
- raise ECollStringList.Create('TCollStringList: Duplicate string');
- if (FListSize = Count) then
- Grow;
- if (Result < Count) then
- Move(FList^[Result],
- FList^[succ(Result)],
- (Count - Result) * sizeof(TCollStrItem));
- inc(FListCount);
- Initialize(FList^[Result]);
- FList^[Result].csiStr := aSt;
- FList^[Result].csiSS := FCollation.ConvertText(aSt);
- end;
- {--------}
- procedure TCollStringList.Delete(aIndex : integer);
- begin
- if not ((0 <= aIndex) and (aIndex < Count)) then
- raise ECollStringList.Create('TCollStringList: Index out of bounds');
- Finalize(FList^[aIndex]);
- FList^[aIndex].csiSS.Free;
- dec(FListCount);
- if (aIndex < Count) then
- Move(FList^[succ(aIndex)],
- FList^[aIndex],
- (Count - aIndex) * sizeof(TCollStrItem));
- end;
- {--------}
- function TCollStringList.Find(const aSt : string; var aIndex : integer) : boolean;
- var
- SS : TSortString;
- L, R, M : integer;
- CompResult : integer;
- begin
- Result := false;
- if Count = 0 then begin
- aIndex := 0;
- Exit;
- end;
- SS := FCollation.ConvertText(aSt);
- try
- L := 0;
- R := pred(Count);
- repeat
- M := (L + R) div 2;
- CompResult :=
- FCollation.CompareSortStrings(FList^[M].csiSS, SS);
- if CompResult < 0 then
- L := succ(M)
- else if CompResult > 0 then
- R := pred(M)
- else {strings are equal} begin
- Result := true;
- aIndex := M;
- Exit;
- end;
- until (L > R);
- aIndex := L;
- finally
- SS.Free;
- end;{try..finally}
- end;
- {--------}
- function TCollStringList.GetObject(aIndex : integer) : TObject;
- begin
- if not ((0 <= aIndex) and (aIndex < Count)) then
- raise ECollStringList.Create('TCollStringList: Index out of bounds');
- Result := FList^[aIndex].csiObj;
- end;
- {--------}
- function TCollStringList.GetString(aIndex : integer) : string;
- begin
- if not ((0 <= aIndex) and (aIndex < Count)) then
- raise ECollStringList.Create('TCollStringList: Index out of bounds');
- Result := FList^[aIndex].csiStr;
- end;
- {--------}
- procedure TCollStringList.SetObject(aIndex : integer; aObj : TObject);
- begin
- if not ((0 <= aIndex) and (aIndex < Count)) then
- raise ECollStringList.Create('TCollStringList: Index out of bounds');
- FList^[aIndex].csiObj := aObj;
- end;
- {--------}
- procedure TCollStringList.Grow;
- begin
- if (FList = nil) then begin
- GetMem(FList, ListDelta * sizeof(TCollStrItem));
- FListSize := ListDelta;
- FListCount := 0;
- end
- else {list already exists} begin
- ReallocMem(FList, (FListSize + ListDelta) * sizeof(TCollStrItem));
- inc(FListSize, ListDelta);
- end;
- end;
- {====================================================================}
-
- end.
-